package mmc.objects;

import static org.lwjgl.opengl.ARBBufferObject.*;
import static org.lwjgl.opengl.ARBVertexBufferObject.*;
import static org.lwjgl.opengl.GL11.*;

import java.nio.ByteBuffer;

import org.lwjgl.opengl.GL11;

import mmc.EngineObject;
import mmc.Scene;
import mmc.gl.shader.OrbShader;
import mmc.gl.shader.ShaderProgram;

@SuppressWarnings("serial")
public class Orb extends EngineObject{

	transient int arbVertex = 0;
	transient int arbIndex = 0;
	transient float radius;
	transient int quads;
	
	//transient DiffusedRandomMap height;
	
	private int seed;
	
	public Orb(float x, float y, float z) {
		super(x, y, z);
		seed = (int) (Math.random()*100);
	}
	
	@Override
	public void initOnClient(Scene scene) {
		//Random r = new Random(seed);
		
		//height = new DiffusedRandomMap(r.nextLong(), 32);
		radius = 3;// + r.nextFloat()*3;
		
		double perimeter = 2*Math.PI*radius;
		double targetEdgeLength = 0.1f;
		int lines = (int) (perimeter/4/targetEdgeLength)+1;
		
		System.out.println("lines="+lines);
		arbVertex = glGenBuffersARB();
		arbIndex = glGenBuffersARB();
		
		//vertex
		int bufferSize = 4*4* lines*(lines+1)/2; //1+2+3+4+5+....+n
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, arbVertex);
		glBufferDataARB(GL_ARRAY_BUFFER_ARB, bufferSize, GL_STATIC_DRAW_ARB);
		ByteBuffer buffer = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB, bufferSize, null);
		
		System.out.println("points: "+lines*(lines+1)/2);
		double latitude = Math.PI/2; //north
		double dlat = latitude/lines;
		for(int i=0;i<lines;i++){
			float sinlat = (float) Math.sin(latitude);
			float coslat = (float) Math.cos(latitude);
			
			double longitude = 0; //east
			double dlong = Math.PI/2 / i;
			for(int j=0;j<=i;j++){
				float sinlong = (float) Math.sin(longitude);
				float coslong = (float) Math.cos(longitude);
				
				buffer.putFloat(coslat*coslong);
				buffer.putFloat(sinlat);
				buffer.putFloat(coslat*sinlong);
				buffer.putFloat(0.1f/*/height.interpolate(i, j, lines, lines)*/);
				
				longitude += dlong; //go west
			}
			
			latitude -= dlat; //go south
		}
		
		buffer.flip();
		glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
		
		//index
		System.out.println((lines-1)*(lines-2)/2+" quads?");
		bufferSize = 4*4*(lines-1)*(lines-2)/2;
		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, arbIndex);
		glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufferSize, GL_STATIC_DRAW_ARB);
		buffer = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB, bufferSize, null);
		
		quads = 0;
		for(int i=1;i<lines-1;i++){
			
			int prevLineStart = (i-1)*(i)/2;
			int lineStart = prevLineStart + i;
			
			for(int j=1;j<i;j++){
				buffer.putInt(prevLineStart);
				buffer.putInt(lineStart);
				buffer.putInt(++lineStart);
				buffer.putInt(++prevLineStart);
				quads++;
			}
			
			buffer.putInt(prevLineStart);
			buffer.putInt(lineStart++);
			buffer.putInt(lineStart);
			buffer.putInt(lineStart);
			quads++;
		}
		
		System.out.println(quads+" quads!");
		
		buffer.flip();
		glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
	}
	
	@Override
	public void render(EngineObject observer) {
		OrbShader s = OrbShader.get();
		s.use();
		s.setRadius(radius);
		
		glPushMatrix();
		glTranslatef(x, y, z);
		
		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, arbIndex);	
		glEnableClientState(GL11.GL_VERTEX_ARRAY);
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, arbVertex);
		glVertexPointer(4, GL_FLOAT, 4*4, 0);
		
		glDrawElements(GL_QUADS,4*quads,GL_UNSIGNED_INT,0);
		
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
		
		glDisableClientState(GL11.GL_VERTEX_ARRAY);
		
		glPopMatrix();
		
		ShaderProgram.useDefault();
	}

	@Override
	public void update(float dt) {
		
	}

	@Override
	public void dispose() {
		if(arbVertex!=0){
			glDeleteBuffersARB(arbVertex);
			glDeleteBuffersARB(arbIndex);
			arbVertex = 0;
			arbIndex = 0;
		}
	}

	@Override
	public boolean copyTo(EngineObject o) {
		o.x = super.x;
		o.y = super.y;
		o.z = super.z;
		o.health = super.health;
		((Orb)o).seed = seed;
		
		return true;
	}
}
